package com.school.sports.controller;

import com.baomidou.mybatisplus.core.metadata.IPage;
import com.school.sports.entity.FileInfo;
import com.school.sports.service.FileInfoService;
import com.school.sports.service.ImageProcessingService;
import com.school.sports.common.Result;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;

import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * 文件管理控制器
 * 处理文件上传、下载、图片处理等请求
 */
@RestController
@RequestMapping("/api/file")
@CrossOrigin
public class FileManagementController {

    private static final Logger logger = LoggerFactory.getLogger(FileManagementController.class);

    @Autowired
    private FileInfoService fileInfoService;

    @Autowired
    private ImageProcessingService imageProcessingService;

    /**
     * 分页查询文件列表
     * @param currentPage 当前页码
     * @param pageSize 每页显示数量
     * @param fileInfo 查询条件
     * @return 分页结果
     */
    @GetMapping("/page/{currentPage}/{pageSize}")
    @PreAuthorize("hasAnyRole('ADMIN', 'TEACHER')")
    public Result<IPage<FileInfo>> getFilePage(
            @PathVariable("currentPage") Integer currentPage,
            @PathVariable("pageSize") Integer pageSize,
            FileInfo fileInfo) {

        logger.info("分页查询文件列表，当前页码：{}，每页条数：{}", currentPage, pageSize);

        // 参数校验
        if (currentPage == null || currentPage <= 0) {
            currentPage = 1;
        }
        if (pageSize == null || pageSize <= 0) {
            pageSize = 10;
        }

        try {
            IPage<FileInfo> page = fileInfoService.getPage(currentPage, pageSize, fileInfo);
            logger.info("查询文件列表成功，共{}条记录", page.getTotal());
            return Result.success(page);
        } catch (Exception e) {
            logger.error("查询文件列表失败：{}", e.getMessage(), e);
            return Result.fail("查询失败：" + e.getMessage());
        }
    }

    /**
     * 单文件上传 - 安全加固版本
     * 添加文件类型白名单验证和大小限制
     * @param file 上传的文件
     * @param relatedType 关联类型
     * @param relatedId 关联ID
     * @param description 文件描述
     * @return 上传结果
     */
    @PostMapping("/upload")
    @PreAuthorize("hasAnyRole('ADMIN', 'TEACHER', 'STUDENT', 'REFEREE', 'VOLUNTEER')")
    public Result<FileInfo> uploadFile(
            @RequestParam("file") MultipartFile file,
            @RequestParam(value = "relatedType", required = false) String relatedType,
            @RequestParam(value = "relatedId", required = false) Long relatedId,
            @RequestParam(value = "description", required = false) String description) {

        logger.info("开始上传文件：{}", file.getOriginalFilename());

        try {
            // 文件安全验证
            Result<String> validation = validateFile(file);
            if (!validation.getCode().equals(200)) {
                return Result.fail(validation.getMessage());
            }

            // 从上下文获取当前用户ID（这里简化处理，实际应该从SecurityContext获取）
            Long uploadUserId = getCurrentUserId();

            FileInfo fileInfo = fileInfoService.uploadFile(file, relatedType, relatedId, description, uploadUserId);
            logger.info("文件上传成功：{}", fileInfo.getOriginalName());
            return Result.success(fileInfo);
        } catch (Exception e) {
            logger.error("文件上传失败：{}", e.getMessage(), e);
            return Result.fail("上传失败：" + e.getMessage());
        }
    }

    /**
     * 批量文件上传 - 安全加固版本
     * 添加文件类型白名单验证和大小限制
     * @param files 上传的文件列表
     * @param relatedType 关联类型
     * @param relatedId 关联ID
     * @param description 文件描述
     * @return 上传结果
     */
    @PostMapping("/upload/batch")
    @PreAuthorize("hasAnyRole('ADMIN', 'TEACHER', 'STUDENT', 'REFEREE', 'VOLUNTEER')")
    public Result<List<FileInfo>> uploadFiles(
            @RequestParam("files") MultipartFile[] files,
            @RequestParam(value = "relatedType", required = false) String relatedType,
            @RequestParam(value = "relatedId", required = false) Long relatedId,
            @RequestParam(value = "description", required = false) String description) {

        logger.info("开始批量上传文件，文件数量：{}", files.length);

        try {
            // 验证每个文件的安全性
            for (MultipartFile file : files) {
                Result<String> validation = validateFile(file);
                if (!validation.getCode().equals(200)) {
                    return Result.fail("文件 " + file.getOriginalFilename() + " 验证失败：" + validation.getMessage());
                }
            }

            Long uploadUserId = getCurrentUserId();
            List<FileInfo> fileInfos = fileInfoService.uploadFiles(files, relatedType, relatedId, description, uploadUserId);
            logger.info("批量上传文件成功，成功上传{}个文件", fileInfos.size());
            return Result.success(fileInfos);
        } catch (Exception e) {
            logger.error("批量上传文件失败：{}", e.getMessage(), e);
            return Result.fail("批量上传失败：" + e.getMessage());
        }
    }

    /**
     * 下载文件
     * @param fileId 文件ID
     * @param response HTTP响应对象
     */
    @GetMapping("/download/{fileId}")
    @PreAuthorize("hasAnyRole('ADMIN', 'TEACHER', 'STUDENT', 'REFEREE', 'VOLUNTEER')")
    public void downloadFile(@PathVariable("fileId") Long fileId, HttpServletResponse response) {
        logger.info("开始下载文件，ID：{}", fileId);

        try {
            fileInfoService.downloadFile(fileId, response);
            logger.info("文件下载成功，ID：{}", fileId);
        } catch (Exception e) {
            logger.error("文件下载失败：{}", e.getMessage(), e);
            response.setStatus(HttpStatus.INTERNAL_SERVER_ERROR.value());
        }
    }

    /**
     * 预览文件（主要用于图片）
     * @param fileId 文件ID
     * @return 文件内容
     */
    @GetMapping("/preview/{fileId}")
    @PreAuthorize("hasAnyRole('ADMIN', 'TEACHER', 'STUDENT', 'REFEREE', 'VOLUNTEER')")
    public ResponseEntity<byte[]> previewFile(@PathVariable("fileId") Long fileId) {
        logger.info("预览文件，ID：{}", fileId);

        try {
            FileInfo fileInfo = fileInfoService.getById(fileId);
            if (fileInfo == null) {
                return ResponseEntity.notFound().build();
            }

            // 这里简化处理，实际应该读取文件内容
            // byte[] fileContent = Files.readAllBytes(Paths.get(fileInfo.getFilePath()));
            // return ResponseEntity.ok()
            //         .contentType(MediaType.parseMediaType(fileInfo.getMimeType()))
            //         .header(HttpHeaders.CONTENT_DISPOSITION, "inline; filename=\"" + fileInfo.getOriginalName() + "\"")
            //         .body(fileContent);

            return ResponseEntity.ok().build();
        } catch (Exception e) {
            logger.error("预览文件失败：{}", e.getMessage(), e);
            return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).build();
        }
    }

    /**
     * 删除文件
     * @param fileId 文件ID
     * @return 删除结果
     */
    @DeleteMapping("/{fileId}")
    @PreAuthorize("hasAnyRole('ADMIN', 'TEACHER')")
    public Result<String> deleteFile(@PathVariable("fileId") Long fileId) {
        logger.info("删除文件，ID：{}", fileId);

        try {
            boolean result = fileInfoService.deletePhysicalFile(fileId);
            if (result) {
                logger.info("文件删除成功，ID：{}", fileId);
                return Result.success("删除成功");
            } else {
                logger.warn("文件删除失败，ID：{}", fileId);
                return Result.fail("删除失败");
            }
        } catch (Exception e) {
            logger.error("删除文件失败：{}", e.getMessage(), e);
            return Result.fail("删除失败：" + e.getMessage());
        }
    }

    /**
     * 根据关联信息获取文件列表
     * @param relatedType 关联类型
     * @param relatedId 关联ID
     * @return 文件列表
     */
    @GetMapping("/related/{relatedType}/{relatedId}")
    @PreAuthorize("hasAnyRole('ADMIN', 'TEACHER', 'STUDENT', 'REFEREE', 'VOLUNTEER')")
    public Result<List<FileInfo>> getFilesByRelatedInfo(
            @PathVariable("relatedType") String relatedType,
            @PathVariable("relatedId") Long relatedId) {

        logger.info("根据关联信息查询文件，类型：{}，ID：{}", relatedType, relatedId);

        try {
            List<FileInfo> files = fileInfoService.getFilesByRelatedInfo(relatedType, relatedId);
            logger.info("查询到{}个关联文件", files.size());
            return Result.success(files);
        } catch (Exception e) {
            logger.error("查询关联文件失败：{}", e.getMessage(), e);
            return Result.fail("查询失败：" + e.getMessage());
        }
    }

    /**
     * 获取用户文件列表
     * @param userId 用户ID（可选，不提供则查询当前用户）
     * @return 文件列表
     */
    @GetMapping("/user/{userId}")
    @PreAuthorize("hasAnyRole('ADMIN', 'TEACHER', 'STUDENT', 'REFEREE', 'VOLUNTEER')")
    public Result<List<FileInfo>> getUserFiles(@PathVariable(value = "userId", required = false) Long userId) {
        try {
            if (userId == null) {
                userId = getCurrentUserId();
            }

            List<FileInfo> files = fileInfoService.getFilesByUserId(userId);
            logger.info("查询到用户{}的{}个文件", userId, files.size());
            return Result.success(files);
        } catch (Exception e) {
            logger.error("查询用户文件失败：{}", e.getMessage(), e);
            return Result.fail("查询失败：" + e.getMessage());
        }
    }

    /**
     * 获取用户文件统计信息
     * @param userId 用户ID（可选）
     * @return 统计信息
     */
    @GetMapping("/statistics/{userId}")
    @PreAuthorize("hasAnyRole('ADMIN', 'TEACHER', 'STUDENT', 'REFEREE', 'VOLUNTEER')")
    public Result<Map<String, Object>> getUserFileStatistics(@PathVariable(value = "userId", required = false) Long userId) {
        try {
            if (userId == null) {
                userId = getCurrentUserId();
            }

            Long totalSize = fileInfoService.getUserTotalFileSize(userId);
            List<FileInfo> files = fileInfoService.getFilesByUserId(userId);

            Map<String, Object> statistics = new HashMap<>();
            statistics.put("totalFiles", files.size());
            statistics.put("totalSize", totalSize);
            statistics.put("totalSizeMB", totalSize / (1024.0 * 1024.0));

            // 按类型统计
            Map<String, Integer> typeCount = new HashMap<>();
            for (FileInfo file : files) {
                String type = file.getFileType();
                typeCount.put(type, typeCount.getOrDefault(type, 0) + 1);
            }
            statistics.put("typeStatistics", typeCount);

            return Result.success(statistics);
        } catch (Exception e) {
            logger.error("获取文件统计信息失败：{}", e.getMessage(), e);
            return Result.fail("获取统计信息失败：" + e.getMessage());
        }
    }

    // ========== 图片处理相关接口 ==========

    /**
     * 图片压缩
     * @param file 图片文件
     * @param quality 压缩质量
     * @param maxWidth 最大宽度
     * @param maxHeight 最大高度
     * @return 压缩后的图片
     */
    @PostMapping("/image/compress")
    @PreAuthorize("hasAnyRole('ADMIN', 'TEACHER', 'STUDENT', 'REFEREE', 'VOLUNTEER')")
    public Result<String> compressImage(
            @RequestParam("file") MultipartFile file,
            @RequestParam(value = "quality", defaultValue = "0.8") float quality,
            @RequestParam(value = "maxWidth", defaultValue = "1920") int maxWidth,
            @RequestParam(value = "maxHeight", defaultValue = "1080") int maxHeight) {

        logger.info("开始压缩图片：{}", file.getOriginalFilename());

        try {
            if (!imageProcessingService.validateImage(file)) {
                return Result.fail("不支持的图片格式");
            }

            byte[] compressedImage = imageProcessingService.compressImage(file, quality, maxWidth, maxHeight);

            // 这里应该保存压缩后的图片并返回URL，简化处理直接返回成功
            logger.info("图片压缩成功：{}", file.getOriginalFilename());
            return Result.success("图片压缩成功");
        } catch (Exception e) {
            logger.error("图片压缩失败：{}", e.getMessage(), e);
            return Result.fail("图片压缩失败：" + e.getMessage());
        }
    }

    /**
     * 生成缩略图
     * @param file 图片文件
     * @param width 缩略图宽度
     * @param height 缩略图高度
     * @return 缩略图URL
     */
    @PostMapping("/image/thumbnail")
    @PreAuthorize("hasAnyRole('ADMIN', 'TEACHER', 'STUDENT', 'REFEREE', 'VOLUNTEER')")
    public Result<String> generateThumbnail(
            @RequestParam("file") MultipartFile file,
            @RequestParam(value = "width", defaultValue = "200") int width,
            @RequestParam(value = "height", defaultValue = "200") int height) {

        logger.info("开始生成缩略图：{}", file.getOriginalFilename());

        try {
            if (!imageProcessingService.validateImage(file)) {
                return Result.fail("不支持的图片格式");
            }

            byte[] thumbnail = imageProcessingService.generateThumbnail(file, width, height);

            // 这里应该保存缩略图并返回URL，简化处理直接返回成功
            logger.info("缩略图生成成功：{}", file.getOriginalFilename());
            return Result.success("缩略图生成成功");
        } catch (Exception e) {
            logger.error("生成缩略图失败：{}", e.getMessage(), e);
            return Result.fail("生成缩略图失败：" + e.getMessage());
        }
    }

    /**
     * 添加水印
     * @param file 图片文件
     * @param watermarkText 水印文字
     * @param position 水印位置
     * @param opacity 透明度
     * @return 处理后的图片URL
     */
    @PostMapping("/image/watermark")
    @PreAuthorize("hasAnyRole('ADMIN', 'TEACHER', 'STUDENT', 'REFEREE', 'VOLUNTEER')")
    public Result<String> addWatermark(
            @RequestParam("file") MultipartFile file,
            @RequestParam("watermarkText") String watermarkText,
            @RequestParam(value = "position", defaultValue = "bottom-right") String position,
            @RequestParam(value = "opacity", defaultValue = "0.5") float opacity) {

        logger.info("开始添加水印：{}", file.getOriginalFilename());

        try {
            if (!imageProcessingService.validateImage(file)) {
                return Result.fail("不支持的图片格式");
            }

            byte[] watermarkedImage = imageProcessingService.addWatermark(file, watermarkText, position, opacity);

            // 这里应该保存处理后的图片并返回URL，简化处理直接返回成功
            logger.info("水印添加成功：{}", file.getOriginalFilename());
            return Result.success("水印添加成功");
        } catch (Exception e) {
            logger.error("添加水印失败：{}", e.getMessage(), e);
            return Result.fail("添加水印失败：" + e.getMessage());
        }
    }

    /**
     * 获取图片信息
     * @param file 图片文件
     * @return 图片信息
     */
    @PostMapping("/image/info")
    @PreAuthorize("hasAnyRole('ADMIN', 'TEACHER', 'STUDENT', 'REFEREE', 'VOLUNTEER')")
    public Result<Map<String, Object>> getImageInfo(@RequestParam("file") MultipartFile file) {
        logger.info("获取图片信息：{}", file.getOriginalFilename());

        try {
            if (!imageProcessingService.validateImage(file)) {
                return Result.fail("不支持的图片格式");
            }

            Map<String, Object> imageInfo = imageProcessingService.getImageInfo(file);
            logger.info("获取图片信息成功：{}", file.getOriginalFilename());
            return Result.success(imageInfo);
        } catch (Exception e) {
            logger.error("获取图片信息失败：{}", e.getMessage(), e);
            return Result.fail("获取图片信息失败：" + e.getMessage());
        }
    }

    // ========== 私有辅助方法 ==========

    /**
     * 文件安全验证 - 验证文件类型和大小
     * @param file 上传的文件
     * @return 验证结果
     */
    private Result<String> validateFile(MultipartFile file) {
        // 1. 检查文件是否为空
        if (file == null || file.isEmpty()) {
            return Result.fail("文件不能为空");
        }

        // 2. 检查文件大小（限制为10MB）
        long maxSize = 10 * 1024 * 1024; // 10MB
        if (file.getSize() > maxSize) {
            return Result.fail("文件大小不能超过10MB");
        }

        // 3. 检查文件名是否合法
        String originalFilename = file.getOriginalFilename();
        if (originalFilename == null || originalFilename.trim().isEmpty()) {
            return Result.fail("文件名不能为空");
        }

        // 防止路径遍历攻击
        if (originalFilename.contains("..") || originalFilename.contains("/") || originalFilename.contains("\\")) {
            return Result.fail("文件名包含非法字符");
        }

        // 4. 检查文件扩展名（白名单验证）
        String fileExtension = getFileExtension(originalFilename);
        if (!isAllowedFileType(fileExtension)) {
            return Result.fail("不支持的文件类型：" + fileExtension + "，支持的类型：jpg, jpeg, png, gif, pdf, doc, docx, xls, xlsx, txt, zip");
        }

        // 5. 检查MIME类型
        String mimeType = file.getContentType();
        if (!isAllowedMimeType(mimeType, fileExtension)) {
            return Result.fail("文件类型与扩展名不匹配或不被允许");
        }

        return Result.success("文件验证通过");
    }

    /**
     * 获取文件扩展名
     * @param filename 文件名
     * @return 扩展名（小写）
     */
    private String getFileExtension(String filename) {
        if (filename == null || filename.lastIndexOf(".") == -1) {
            return "";
        }
        return filename.substring(filename.lastIndexOf(".") + 1).toLowerCase();
    }

    /**
     * 检查文件类型是否在白名单中
     * @param extension 文件扩展名
     * @return 是否允许
     */
    private boolean isAllowedFileType(String extension) {
        // 允许的文件类型白名单
        String[] allowedTypes = {
            "jpg", "jpeg", "png", "gif",  // 图片
            "pdf",  // PDF文档
            "doc", "docx",  // Word文档
            "xls", "xlsx",  // Excel表格
            "txt",  // 文本文件
            "zip"  // 压缩文件
        };

        for (String allowedType : allowedTypes) {
            if (allowedType.equals(extension)) {
                return true;
            }
        }
        return false;
    }

    /**
     * 检查MIME类型是否合法
     * @param mimeType MIME类型
     * @param extension 文件扩展名
     * @return 是否允许
     */
    private boolean isAllowedMimeType(String mimeType, String extension) {
        if (mimeType == null) {
            return false;
        }

        // 图片类型验证
        if (("jpg".equals(extension) || "jpeg".equals(extension)) &&
            (mimeType.equals("image/jpeg") || mimeType.equals("image/jpg"))) {
            return true;
        }
        if ("png".equals(extension) && mimeType.equals("image/png")) {
            return true;
        }
        if ("gif".equals(extension) && mimeType.equals("image/gif")) {
            return true;
        }

        // 文档类型验证
        if ("pdf".equals(extension) && mimeType.equals("application/pdf")) {
            return true;
        }
        if ("doc".equals(extension) && mimeType.equals("application/msword")) {
            return true;
        }
        if ("docx".equals(extension) && mimeType.equals("application/vnd.openxmlformats-officedocument.wordprocessingml.document")) {
            return true;
        }
        if ("xls".equals(extension) && mimeType.equals("application/vnd.ms-excel")) {
            return true;
        }
        if ("xlsx".equals(extension) && mimeType.equals("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet")) {
            return true;
        }

        // 文本类型验证
        if ("txt".equals(extension) && mimeType.equals("text/plain")) {
            return true;
        }

        // 压缩文件验证
        if ("zip".equals(extension) && mimeType.equals("application/zip")) {
            return true;
        }

        return false;
    }

    /**
     * 获取当前用户ID（简化实现）
     */
    private Long getCurrentUserId() {
        // 实际应该从SecurityContext获取当前用户信息
        // 这里返回1作为示例
        return 1L;
    }
}